package com.eclipse.training.ui;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;

import org.eclipse.swt.dnd.ByteArrayTransfer;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.TransferData;

import com.eclipse.training.model.AbstractUniverseElement;

public class ElementsArrayDataTransfer extends ByteArrayTransfer {

	private static final String MYTYPENAME = "ElementsArrayDataTransfer";

	private static final int MYTYPEID = registerType(MYTYPENAME);

	private static ElementsArrayDataTransfer _instance = new ElementsArrayDataTransfer();

	public static ElementsArrayDataTransfer getInstance() {
		return _instance;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.swt.dnd.ByteArrayTransfer#javaToNative(java.lang.Object,
	 * org.eclipse.swt.dnd.TransferData)
	 */
	public void javaToNative(Object object, TransferData transferData) {
		if (!checkMyType(object) || !isSupportedType(transferData)) {
			DND.error(DND.ERROR_INVALID_DATA);
		}
		AbstractUniverseElement[] myTypes = (AbstractUniverseElement[]) object;
		try {
			// write data to a byte array and then ask super to convert to
			// pMedium
			ByteArrayOutputStream out = new ByteArrayOutputStream();
			DataOutputStream writeOut = new DataOutputStream(out);
			for (int i = 0, length = myTypes.length; i < length; i++) {
				writeOut.writeInt(myTypes[i].getName().getBytes().length);
				writeOut.write(myTypes[i].getName().getBytes());
				writeOut.writeInt(myTypes[i].getConstellation().getBytes().length);
				writeOut.write(myTypes[i].getConstellation().getBytes());
				writeOut.writeInt(myTypes[i].getDesignation().getBytes().length);
				writeOut.write(myTypes[i].getDesignation().getBytes());
			}
			byte[] buffer = out.toByteArray();
			writeOut.close();
			super.javaToNative(buffer, transferData);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.eclipse.swt.dnd.ByteArrayTransfer#nativeToJava(org.eclipse.swt.dnd
	 * .TransferData)
	 */
	public Object nativeToJava(TransferData transferData) {
		if (isSupportedType(transferData)) {
			byte[] buffer = (byte[]) super.nativeToJava(transferData);
			if (buffer == null)
				return null;

			AbstractUniverseElement[] myData = new AbstractUniverseElement[0];
			try {
				ByteArrayInputStream in = new ByteArrayInputStream(buffer);
				DataInputStream readIn = new DataInputStream(in);
				while (readIn.available() > 0) {
					AbstractUniverseElement datum = new AbstractUniverseElement();
					int size = readIn.readInt();
					byte[] buf = new byte[size];
					readIn.read(buf);
					datum.setName(buf.toString());

					size = readIn.readInt();
					buf = new byte[size];
					readIn.read(buf);
					datum.setConstellation(buf.toString());

					size = readIn.readInt();
					buf = new byte[size];
					readIn.read(buf);
					datum.setDesignation(buf.toString());

					AbstractUniverseElement[] newMyData = new AbstractUniverseElement[myData.length + 1];
					System.arraycopy(myData, 0, newMyData, 0, myData.length);
					newMyData[myData.length] = datum;
					myData = newMyData;
				}
				readIn.close();
			} catch (IOException ex) {
				return null;
			}
			return myData;
		}

		return null;
	}

	protected String[] getTypeNames() {
		return new String[] { MYTYPENAME };
	}

	protected int[] getTypeIds() {
		return new int[] { MYTYPEID };
	}

	boolean checkMyType(Object object) {
		if (object == null || !(object instanceof AbstractUniverseElement[])
				|| ((AbstractUniverseElement[]) object).length == 0) {
			return false;
		}
		AbstractUniverseElement[] myTypes = (AbstractUniverseElement[]) object;
		for (int i = 0; i < myTypes.length; i++) {
			if (myTypes[i] == null || myTypes[i] == null) {
				return false;
			}
		}
		return true;
	}

	protected boolean validate(Object object) {
		return checkMyType(object);
	}

}
